package jumpingnotes.restlet.resource;

import static jumpingnotes.restlet.ErrorCode.NO_PERMISSION;
import static jumpingnotes.restlet.ErrorCode.OBJECT_NOT_FOUND;
import static jumpingnotes.restlet.ErrorCode.SERVER_INTERNAL_ERROR;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import jumpingnotes.model.entity.Member;
import jumpingnotes.restlet.JsonMapping;
import jumpingnotes.security.Session;
import jumpingnotes.security.SessionManager;

import org.json.JSONObject;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.ResourceException;
import org.restlet.resource.Variant;

public class MemberFriendsOnlineResource extends BaseResource
{
	private Member member = null;
	private int startIndex = 0;
	private int count = 10;

	private ConcurrentHashMap<String, Session> sessionMap;

	@Override
	public void init(Context context, Request request, Response response)
	{
		super.init(context, request, response);

		getVariants().add(new Variant(MediaType.APPLICATION_JSON));

		try
		{
			sessionId = (String) getRequest().getAttributes().get("sessionId");
			checkPermission();

			if (hasPermission())
			{
				// URL: "/members/{memberId}/friendsonline?startIndex={startIndex}&amp;count={count}"
				String memberIdStr = (String) getRequest().getAttributes().get("memberId");

				String startIndexStr = (String) getRequest().getAttributes().get("startIndex");
				String countStr = (String) getRequest().getAttributes().get("count");

				startIndex = Integer.valueOf(startIndexStr);
				count = Integer.valueOf(countStr);

				if ("me".equalsIgnoreCase(memberIdStr))
				{
					String email = session.getEmail();
					member = service.findMemberByEmail(email);
				}
				else
				{
					int memberId = Integer.parseInt(memberIdStr);
					member = service.findMemberById(memberId);
				}

				// get session manager
				SessionManager sessionManager = service.getSessionManager();
				sessionMap = sessionManager.getSessionMap();
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public Representation represent(Variant variant) throws ResourceException
	{
		if (!hasPermission())
		{
			return createErrorRepresentation(NO_PERMISSION);
		}

		if (member == null)
		{
			return createErrorRepresentation(OBJECT_NOT_FOUND);
		}

		try
		{
			// get all friends
			List<Member> memberList = service.findMemberByFriendMemberId(member.getMemberId(), -1, -1);

			// filter online friends
			List<Member> onlineList = new ArrayList<Member>();
			for (Member member : memberList)
			{
				String email = member.getEmail();
				if (userOnline(email))
				{
					onlineList.add(member);
				}
			}

			// support paging
			List<Member> pagingList;
			if (startIndex >= 0 && count > 0)
			{
				int start = Math.min(startIndex, onlineList.size());
				int end = Math.min(startIndex + count, onlineList.size());
				pagingList = onlineList.subList(start, end);
			}
			else
			{
				pagingList = onlineList;
			}

			// create json object
			List<JSONObject> memberJsonList = new ArrayList<JSONObject>();
			for (Member member : pagingList)
			{
				JSONObject memberJson = JsonMapping.map(member);
				memberJsonList.add(memberJson);
			}

			JSONObject membersJson = new JSONObject();
			membersJson.put("count", onlineList.size());
			membersJson.put("members", memberJsonList);

			return createJsonRepresentation(membersJson);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return createErrorRepresentation(SERVER_INTERNAL_ERROR);
		}
	}

	private boolean userOnline(String email)
	{
		for (Enumeration<Session> e = sessionMap.elements(); e.hasMoreElements();)
		{
			Session session = e.nextElement();
			if (session.getEmail().equals(email))
			{
				return true;
			}
		}
		return false;
	}
}
